package com.ruoyi.framework.dataPermission;


import com.ruoyi.tool.JsqlParserSupport.JsqlParserSupport;
import com.ruoyi.tool.PluginUtils.PluginUtils;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectVisitorAdapter;
import net.sf.jsqlparser.statement.select.SetOperationList;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.Connection;
import java.util.Properties;

@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class MybatisDataPermissionInterceptor extends JsqlParserSupport implements Interceptor {

    private final DataPermissionHandler dataPermissionHandler = new DataPermissionHandler();


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();

        // 检查是否无效 无数据权限注解
        if (DataPermissionHolder.getDataPermission() == null) {
            return invocation.proceed();
        }

        BoundSql boundSql = statementHandler.getBoundSql();
        // 解析 sql 分配对应方法
        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
        mpBs.sql(parserSingle(mpBs.sql()));

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 可以获取配置的属性
    }

    @Override
    protected void processSelect(Select select, int index, String sql) {
        select.accept(new SelectVisitorAdapter() {
            @Override
            public void visit(PlainSelect plainSelect) {
                setWhere(plainSelect);
            }

            @Override
            public void visit(SetOperationList setOpList) {
                setOpList.getSelects().forEach(s -> s.accept(this));
            }
        });
    }

    /**
     * 设置 where 条件
     *
     * @param plainSelect       查询对象
     */
    protected void setWhere(PlainSelect plainSelect) {
        Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), true);
        if (null != sqlSegment) {
            plainSelect.setWhere(sqlSegment);
        }
    }
}
